home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Dr. Windows 3
/
dr win3.zip
/
dr win3
/
NEW_TECH
/
AWKSRC.ZIP
/
EVAL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-09-27
|
32KB
|
1,223 lines
/*
* eval.c - gawk parse tree interpreter
*/
/*
* Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
*
* GAWK is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GAWK is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GAWK; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "awk.h"
extern double pow P((double x, double y));
extern double modf P((double x, double *yp));
extern double fmod P((double x, double y));
static int eval_condition P((NODE *tree));
static NODE *op_assign P((NODE *tree));
static NODE *func_call P((NODE *name, NODE *arg_list));
static NODE *match_op P((NODE *tree));
NODE *_t; /* used as a temporary in macros */
#ifdef MSDOS
double _msc51bug; /* to get around a bug in MSC 5.1 */
#endif
NODE *ret_node;
int OFSlen;
int ORSlen;
int OFMTidx;
int CONVFMTidx;
/* Macros and variables to save and restore function and loop bindings */
/*
* the val variable allows return/continue/break-out-of-context to be
* caught and diagnosed
*/
#define PUSH_BINDING(stack, x, val) (memcpy ((char *)(stack), (char *)(x), sizeof (jmp_buf)), val++)
#define RESTORE_BINDING(stack, x, val) (memcpy ((char *)(x), (char *)(stack), sizeof (jmp_buf)), val--)
static jmp_buf loop_tag; /* always the current binding */
static int loop_tag_valid = 0; /* nonzero when loop_tag valid */
static int func_tag_valid = 0;
static jmp_buf func_tag;
extern int exiting, exit_val;
/*
* This table is used by the regexp routines to do case independant
* matching. Basically, every ascii character maps to itself, except
* uppercase letters map to lower case ones. This table has 256
* entries, which may be overkill. Note also that if the system this
* is compiled on doesn't use 7-bit ascii, casetable[] should not be
* defined to the linker, so gawk should not load.
*
* Do NOT make this array static, it is used in several spots, not
* just in this file.
*/
#if 'a' == 97 /* it's ascii */
char casetable[] = {
'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
/* ' ' '!' '"' '#' '$' '%' '&' ''' */
'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
/* '(' ')' '*' '+' ',' '-' '.' '/' */
'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
/* '0' '1' '2' '3' '4' '5' '6' '7' */
'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
/* '8' '9' ':' ';' '<' '=' '>' '?' */
'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
/* '@' 'A' 'B' 'C' 'D' 'E' 'F' 'G' */
'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
/* 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' */
'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
/* 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W' */
'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
/* 'X' 'Y' 'Z' '[' '\' ']' '^' '_' */
'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
/* '`' 'a' 'b' 'c' 'd' 'e' 'f' 'g' */
'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
/* 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' */
'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
/* 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' */
'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
/* 'x' 'y' 'z' '{' '|' '}' '~' */
'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
'\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
'\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
'\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
'\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
};
#else
#include "You lose. You will need a translation table for your character set."
#endif
/*
* Tree is a bunch of rules to run. Returns zero if it hit an exit()
* statement
*/
int
interpret(tree)
register NODE *volatile tree;
{
jmp_buf volatile loop_tag_stack; /* shallow binding stack for loop_tag */
static jmp_buf rule_tag; /* tag the rule currently being run, for NEXT
* and EXIT statements. It is static because
* there are no nested rules */
register NODE *volatile t = NULL; /* temporary */
NODE **volatile lhs; /* lhs == Left Hand Side for assigns, etc */
NODE *volatile stable_tree;
int volatile traverse = 1; /* True => loop thru tree (Node_rule_list) */
if (tree == NULL)
return 1;
sourceline = tree->source_line;
source = tree->source_file;
switch (tree->type) {
case Node_rule_node:
traverse = 0; /* False => one for-loop iteration only */
/* FALL THROUGH */
case Node_rule_list:
for (t = tree; t != NULL; t = t->rnode) {
if (traverse)
tree = t->lnode;
sourceline = tree->source_line;
source = tree->source_file;
switch (setjmp(rule_tag)) {
case 0: /* normal non-jump */
/* test pattern, if any */
if (tree->lnode == NULL ||
eval_condition(tree->lnode))
(void) interpret(tree->rnode);
break;
case TAG_CONTINUE: /* NEXT statement */
return 1;
case TAG_BREAK:
return 0;
default:
cant_happen();
}
if (!traverse) /* case Node_rule_node */
break; /* don't loop */
}
break;
case Node_statement_list:
for (t = tree; t != NULL; t = t->rnode)
(void) interpret(t->lnode);
break;
case Node_K_if:
if (eval_condition(tree->lnode)) {
(void) interpret(tree->rnode->lnode);
} else {
(void) interpret(tree->rnode->rnode);
}
break;
case Node_K_while:
PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
stable_tree = tree;
while (eval_condition(stable_tree->lnode)) {
switch (setjmp(loop_tag)) {
case 0: /* normal non-jump */
(void) interpret(stable_tree->rnode);
break;
case TAG_CONTINUE: /* continue statement */
break;
case TAG_BREAK: /* break statement */
RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
return 1;
default:
cant_happen();
}
}
RESTORE_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
break;
case Node_K_do:
PUSH_BINDING(loop_tag_stack, loop_tag, loop_tag_valid);
stable_tree = tree;
do {
switch (setjmp(loop_tag)) {
case 0: /* normal non-jump */